package main;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;

//Nikolas Wolfe
//4/13/09
//CIS 4930
//Game of Life 2

/* =============================================================================
* Makes, Manages Map Configurations, all File IO
*/

public class ConfigurationManager
{
	// map file
	private static final String configFile = "10x10-map.txt";
	private static final String outputFile = "output-map.txt";
	private static final String dimension = "DIM:";
	
	// color constants
	private static final int WHITE 	= 0xFFFFFFFF;
	private static final int RED 	= 0xFFFF0000; 
	private static final int GREEN 	= 0xFF00FF00;
	private static final int BLUE 	= 0xFF0000FF;
	
	// letter constants
	private static final String W 	= "W";
	private static final String R 	= "R"; 
	private static final String G   = "G";
	private static final String B   = "B";
	
	private final HashMap<String, Integer> stringValueMap;
	private final HashMap<Integer, String> valueStringMap;
	private ToroidalArray<Integer> arr;
	
	private int WIDTH;
	private int HEIGHT;
	
	// supplied filename
	private String fileName;
	
	/* =========================================================================
	 * Constructor
	 */ 
	public ConfigurationManager( int WIDTH, int HEIGHT )
	{
		this.WIDTH = WIDTH;
		this.HEIGHT = HEIGHT;
		this.arr = new ToroidalArray<Integer>( WIDTH, HEIGHT );
		this.stringValueMap = new HashMap<String, Integer>();
		this.valueStringMap = new HashMap<Integer, String>();
		
		stringValueMap.put(W, 	WHITE);
		stringValueMap.put(R, 	RED);
		stringValueMap.put(G, 	GREEN);
		stringValueMap.put(B, 	BLUE);
		
		valueStringMap.put(WHITE, 	W);
		valueStringMap.put(RED, 	R);
		valueStringMap.put(GREEN, 	G);
		valueStringMap.put(BLUE, 	B);
	}
	
	/* =========================================================================
	 * Read config file, load map with data
	 */ 
	public void initialize( String filename ) 
	{
		this.fileName = filename;
		try
		{
			if (fileName == null)
			{
				fileName = configFile;
			}
			FileInputStream input;

			input = new FileInputStream(fileName);

			BufferedReader reader = new BufferedReader(new InputStreamReader(input));
			String dimensionLine = reader.readLine();
			if(dimensionLine.startsWith(dimension))
			{
				String[] dim = dimensionLine.substring(4).split(",");
				this.WIDTH = Integer.parseInt(dim[0]);
				this.HEIGHT = Integer.parseInt(dim[1]);
				arr = new ToroidalArray<Integer>( WIDTH, HEIGHT );
			}
			else {
				System.out.println("Incorrect config file!");
				System.exit(0);
			}

			// input array
			String s = "";
			int i = 0;
			while ((s = reader.readLine()) != null)
			{
				if (s != "")
				{
					String[] split = s.split(",");
					for (int j = 0; j < split.length; ++j)
					{
						arr.set(i, j, stringValueMap.get(split[j]));
					}
				}
				++i;
			}

			reader.close();
			input.close();
		} 
		catch (IOException e)
		{
			System.out.println("File not found!");
			System.exit(0);
		}
	}
	
	/* =========================================================================
	 * Randomly Generate a Map for the specified size
	 */ 
	public void initializeForMe() 
	{
		Random rnd = new Random();
		int[] colors = new int[4];
		colors[0] = stringValueMap.get(G);
		colors[1] = stringValueMap.get(R);
		colors[2] = stringValueMap.get(B);
		colors[3] = stringValueMap.get(W);
		
		for( int i = 0; i < arr.getXMax(); ++i )
		{
			for( int j = 0; j < arr.getYMax(); ++j )
			{
				arr.set(i, j, colors[rnd.nextInt(4)]);
			}
		}
	}
	
	/* =========================================================================
	 * Takes an array, data, outputs a config file
	 */ 
	public void outputFinalConfiguration( ToroidalArray<Integer> arr, 
			int numThreads, int numGenerations, StatService statService ) throws IOException
	{
		// generate output filename
		String outputFilename = "GoL2-";
		if( fileName == null )
		{
			outputFilename += "generated-"; 
		}
		else
		{
			outputFilename += fileName + "-";
		}
		outputFilename += numThreads + "-" + numGenerations + "-" + Timestamp.now(); 
		
		FileOutputStream output = new FileOutputStream( outputFilename + "-map.txt" );
		PrintWriter writer = new PrintWriter(output);
		
		// output dimension heading
		writer.println( dimension + WIDTH + "," + HEIGHT );
		for( int i = 0; i < arr.getXMax(); ++i )
		{
			String s = "";
			for(int j = 0; j < arr.getYMax(); ++j )
			{
				s += valueStringMap.get(arr.get(i,j));
				if( j < arr.getYMax()-1 )
				{
					s += ",";
				}
			}
			writer.println(s);
		}
		writer.close();
		output.close();
		
		// now write the stats report to a file
		outputReport( statService, outputFilename, numThreads, numGenerations );
	}
	
	/* =============================================================================
	 * Write simulation summary to a file
	 */
	private void outputReport( StatService statService, String outputFilename, 
			int numThreads, int numGenerations ) throws IOException
	{
		// print report to screen
		statService.printReport();
		
		// write idential report to file
		FileOutputStream output = new FileOutputStream( outputFilename + ".txt" );
		PrintWriter writer = new PrintWriter(output);
		
		// this is what gets printed in the GameOfLife main class
		writer.println("Nikolas Wolfe");
		writer.println("4/13/09");
		writer.println("CIS 4930");
		writer.println("Game of Life 2\n");
		OpSysSnoop.snoopOsIntoFile(writer);
		writer.println();
		writer.println("------------------------------------------------------------");
		writer.println("================== Conway's Game Of Life ===================");
		writer.println("------------------------------------------------------------");
		writer.println();
		writer.println("******************** Simulation Summary ********************\n");
		writer.println("Number of Threads: " + numThreads );
		writer.println("Number of Generations: " + numGenerations );
		writer.println("Grid Size: " + WIDTH + " X " + HEIGHT + " cells\n" );
		
		// print report summary
		Iterator<String> i = statService.getStringIterator();
		while( i.hasNext() )
		{
			writer.println( i.next() );
		}
		writer.close();
		output.close();
	}
	
	/* =============================================================================
	 * Returns an Array Configuration
	 */
	public ToroidalArray<Integer> getConfiguration()
	{
		return arr;
	}

	/* =============================================================================
	 * Map Parameters
	 */
	public int getWIDTH()
	{
		return WIDTH;
	}

	public int getHEIGHT()
	{
		return HEIGHT;
	}
}
